using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel;
using System.Dynamic;

namespace Test.Utility.Extensions
{
    public static class DictionaryExtensions
    {
        public static V GetValue<T, V>(this IDictionary<T, V> dic, T key, V defaultValue)
        {
            if (dic == null || !dic.ContainsKey(key))
                return defaultValue;
            return dic[key];
        }

        public static IDictionary<T, V> Add<T, V>(this IDictionary<T, V> dic, IEnumerable<KeyValuePair<T, V>> values, bool replaceWhenExists = true)
        {
            if (values != null)
            {
                foreach (var kvp in values)
                {
                    if (dic.ContainsKey(kvp.Key))
                    {
                        if (replaceWhenExists)
                            dic[kvp.Key] = kvp.Value;
                    }
                    else
                    {
                        dic.Add(kvp.Key, kvp.Value);
                    }
                }
            }
            return dic;
        }

        //public static Dictionary<T, V> Add<T, V>(this Dictionary<T, V> dic, object values)
        //{
        //    if (values != null)
        //    {
        //        foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values))
        //        {
        //            object obj2 = descriptor.GetValue(values);
        //            dic.Add(descriptor.Name, obj2);
        //        }
        //    }
        //    return dic;
        //}

        public static string ToFormatString<T, V>(this IDictionary<T, V> dic, string comma = "&", string equal = "=", string leftComma = "", string rightComma = "", Func<T, string> keyToString = null, Func<V, string> valToString = null)
        {
            if (dic == null || dic.Count <= 0)
                return string.Empty;
            if (keyToString == null)
                keyToString = o => o.ToString();
            if (valToString == null)
                valToString = o => o == null ? null : o.ToString();
            StringBuilder sb = new StringBuilder();
            int idx = 0;
            foreach (T key in dic.Keys)
            {
                sb.AppendFormat("{0}{1}{2}{3}{4}", keyToString(key), equal, leftComma, valToString(dic[key]), rightComma);
                if (idx < dic.Count - 1)
                    sb.Append(comma);
                idx++;
            }
            return sb.ToString();
        }

        public static NameValueCollection ToNameValueCollection<T, V>(this IDictionary<T, V> dic, Func<T, string> keyToString = null, Func<V, string> valToString = null)
        {
            if (dic == null)
                return null;
            if (keyToString == null)
                keyToString = o => o.ToString();
            if (valToString == null)
                valToString = o => o == null ? null : o.ToString();
            NameValueCollection nv = new NameValueCollection();
            foreach (var kvp in dic)
            {
                nv.Add(keyToString(kvp.Key), valToString(kvp.Value));
            }
            return nv;
        }


        public static int GetInt<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
        {
            return GetValue<TKey, TValue, int>(dictionary, key);
        }

        public static int GetInt<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, int defaultValue)
        {
            return GetValue<TKey, TValue, int>(dictionary, key, defaultValue);
        }

        public static float GetFloat<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
        {
            return GetValue<TKey, TValue, float>(dictionary, key);
        }

        public static float GetFloat<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, float defaultValue)
        {
            return GetValue<TKey, TValue, float>(dictionary, key, defaultValue);
        }

        public static decimal GetDecimal<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
        {
            return GetValue<TKey, TValue, decimal>(dictionary, key);
        }

        public static decimal GetDecimal<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, decimal defaultValue)
        {
            return GetValue<TKey, TValue, decimal>(dictionary, key, defaultValue);
        }

        public static double GetDouble<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
        {
            return GetValue<TKey, TValue, double>(dictionary, key);
        }

        public static double GetDouble<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, double defaultValue)
        {
            return GetValue<TKey, TValue, double>(dictionary, key, defaultValue);
        }

        public static bool GetBoolean<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
        {
            return GetValue<TKey, TValue, bool>(dictionary, key);
        }

        public static bool GetBoolean<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, bool defaultValue)
        {
            return GetValue<TKey, TValue, bool>(dictionary, key, defaultValue);
        }

        public static string GetString<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
        {
            return GetValue<TKey, TValue, string>(dictionary, key, String.Empty);
        }

        public static string GetString<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, string defaultValue)
        {
            return GetValue<TKey, TValue, string>(dictionary, key, defaultValue);
        }

        public static DateTime GetDateTime<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
        {
            return GetValue<TKey, TValue, DateTime>(dictionary, key);
        }

        public static DateTime GetDateTime<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, DateTime defaultValue)
        {
            return GetValue<TKey, TValue, DateTime>(dictionary, key, defaultValue);
        }

        public static T GetValue<TKey, TValue, T>(this IDictionary<TKey, TValue> dictionary, TKey key)
        {
            return dictionary.GetValue<TKey, TValue, T>(key, default(T));
        }

        public static T GetValue<TKey, TValue, T>(this IDictionary<TKey, TValue> dictionary, TKey key, T defaultValue)
        {
            if (dictionary != null && dictionary.ContainsKey(key) && dictionary[key] != null)
            {
                return dictionary[key].As<T>(defaultValue);
            }

            return defaultValue;
        }


        public static dynamic ToExpendDo(this NameValueCollection collection)
        {
            IDictionary<string, object> expando = new ExpandoObject();
            foreach (var item in collection.AllKeys)
                expando.Add(item, collection.Get(item));
            return expando;
        }

        public static NameValueCollection GetUseful(this NameValueCollection collection, Func<string, bool> predicate)
        {
            var @new = new NameValueCollection();

            foreach (var item in collection.AllKeys)
            {
                if (predicate(item))
                {
                    @new[item] = collection[item];
                }
            }

            return @new;
        }

    }
}
